package com.macrounion.atv.service.utils;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.macrounion.base.service.exception.BusinessException;
import com.macrounion.base.service.utils.BigDecimalUtil;

/**
 * 计算器
 * @author Administrator
 *
 */
public class CalculatorUtils {
	public static double sum(double ...x){
		double d = 0;
		for(double i : x) {
			d=BigDecimalUtil.add(i, d);
		}
		return d;
	}
	public static double min(double ...x){
		double min = x[0];
		if(x.length == 1)
			return min;
		for(double i : x) {
			if(i<min)
				min = i;
		}
		return min;
	}
	// max 返回x,y中较大的值
	public static double max(double ...x){
		double max = x[0];
		if(x.length == 1)
			return max;
		for(double i : x) {
			if(i>max)
				max = i;
		}
		return max;
	}
	//平均值
	public static double avg(double ...x){
		return BigDecimalUtil.div(sum(x), x.length);
	}
	//获取通道值
	public static double c(String id,Map<String,Double> cValues){
		if(cValues == null || !cValues.containsKey(id))
			return 0;
		return cValues.get(id);
	}
	 /**
     * 匹配存数字
     */
    private static String numberString = "(\\d+\\.\\d+|\\d+)|(^[-]\\d+[.]?\\d*$)";
//    private static String numberString ="^[-]\\d+[.]?\\d*$";
//	/**
//     * 不带括号的运算
//     */
//    private static String noParentheses="^[^\\(\\)]+$";
    /**
     * 匹配乘法或者除法
     */
    private static String priorOperatorExp="((([\\-]?)(\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\]))[\\*\\/]((\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\])))";
    /**
     * 匹配加法和减法
     */
    private static String operatorExp="((([\\-]?)(\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\]))[\\+\\-]((\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\])))";
    /**
     * 最小计数单位
     * 
     */
    private static String minExp="^(([\\-]?)(\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\]))[\\+\\-\\*\\/]((\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\]))$";
    /**
     * 计算最小单位四则运算表达式（两个数字）
     * @param exp
     * @return
     */
    private static double calculate(String exp){
        exp=exp.replaceAll("[\\[\\]]", "");
        String number[]=exp.replaceFirst("(\\d)[\\+\\-\\*\\/]", "$1,").split(",");
        BigDecimal number1=new BigDecimal(number[0]);
        BigDecimal number2=new BigDecimal(number[1]);
        BigDecimal result=null;
        
        String operator=exp.replaceFirst("^.*\\d([\\+\\-\\*\\/]).+$", "$1");
        if("+".equals(operator)){
            result=number1.add(number2);
        }else if("-".equals(operator)){
            result=number1.subtract(number2);
        }else if("*".equals(operator)){
            result=number1.multiply(number2);
        }else if("/".equals(operator)){
            //第二个参数为精度，第三个为四色五入的模式
            result=number1.divide(number2,5,BigDecimal.ROUND_CEILING);
        }
        
        return result!=null?result.doubleValue():null;
    }
    private static String parseExp(String expression) {
    	expression = expression.replace("+-", "-").replace("++", "+").replace("--", "+").replace("-+", "-").replace("/+", "/").replace("*+", "*");
    	String expressionF = new String(expression);
    	if(expression.startsWith("+")) {
    		expression = expression.substring(1);
    	}
    	//直接是数字不计算
        if(expression.matches(numberString)){
            return expression;
        }
        //最小表达式计算
        if(expression.matches(minExp)){
            return NF.format(calculate(expression));
        }
		Pattern patt=null;
		try {patt=Pattern.compile(priorOperatorExp);}catch(StackOverflowError e) {throw new ArithmeticException();}
        Matcher mat=patt.matcher(expression);
        if(mat.find()){
            String tempMinExp=mat.group();
            expression=expression.replaceFirst(priorOperatorExp, parseExp(tempMinExp));
        }else{
    		try {patt=Pattern.compile(operatorExp);}catch(StackOverflowError e) {throw new ArithmeticException();}
            mat=patt.matcher(expression);
            if(mat.find()){
                String tempMinExp=mat.group();
                expression=expression.replaceFirst(operatorExp, parseExp(tempMinExp));
            }
        }
//        return parseExp(expression).replace("[", "").replace("]", "");
        if(expression.equals(expressionF))
        	throw new BusinessException(201,"错误的Fx运算公式");
        return parseExp(expression);
	}

    private static java.text.NumberFormat NF = java.text.NumberFormat.getInstance();
    static {
    	NF.setMaximumFractionDigits(15);
		NF.setMinimumFractionDigits(0);
		NF.setGroupingUsed(false);
    }
    /**
     * 计算
     * @param s-公式
     * @param cValues-通道值
     * @return
     */
	public static String getCalculate(String s,Map<String,Double> cValues) {
		s=s.replaceAll("\\s+", "");
		String firStr = new String(s);
		//直接是数字不计算
        if(s.matches(numberString)){
            return s;
        }
        //最小表达式计算
        if(s.matches(minExp)){
            String result=NF.format(calculate(s));
            return result;
        }
		String fn = "";
		String fc = "";
		for(int i=0;i<s.length();i++) {
			char c = s.charAt(i);
			fn = fn+c;
			if(c == '(') {
				fc = "";
			}else if(c != ')'){
				fc  = fc+c;
			}
			if(c == ')')
				break;
		}
		boolean hasLeft  =fn.lastIndexOf('(') > -1;
		String n1 = hasLeft ?fn.substring(0, fn.lastIndexOf('(')):fn;
		String rep = hasLeft?"("+fc+")":fc;
		int f1 = n1.lastIndexOf(',')+1;
		int f2 = n1.lastIndexOf('/')+1;
		int f3 = n1.lastIndexOf('*')+1;
		int f4 = n1.lastIndexOf('+')+1;
		int f5 = n1.lastIndexOf('-')+1;
		int f6 = n1.lastIndexOf('(')+1;
		int max = (int) max(f1,f2,f3,f4,f5,f6);
		fn = n1.substring(max).replace("(", "");
		
		if("c".equals(fn.toLowerCase())) {
			s = s.replace(fn+rep, c(fc,cValues)+"");
		} else if(fc.indexOf(',') < 0) {
			//四则运算
			s = s.replace(rep, parseExp(muldiv(fc)));
		}else {
			String re = "";
			if("sum".equals(fn.toLowerCase())){
				re = ""+sum(convertFromfc(fc));
			}else if("min".equals(fn.toLowerCase())){	// min()
				re = ""+min(convertFromfc(fc));
			}else if("max".equals(fn.toLowerCase())){	// max()
				re = ""+max(convertFromfc(fc));
			}else if("avg".equals(fn.toLowerCase())){	// doubleMe()
				re = ""+avg(convertFromfc(fc));
			}else {
				System.out.println("错误运算符->"+fn);
				System.out.println("错误步骤->"+fc);
				throw new BusinessException(201,"错误的Fx运算公式");
			}
			s = s.replace(fn+rep, re);
		}
//		System.out.println("运算步骤->"+s);
		if(firStr.equals(s))
			throw new BusinessException(201,"错误的Fx运算公式");
		return getCalculate(s,cValues);
//		return s;
	}
	/**
	 * 处理 类似 /- *-的运算
	 * @param fc
	 * @return
	 */
	private static String muldiv(String fc) {
		fc =muldivd(fc,"/-");
		fc =muldivd(fc,"*-");
		return fc;
	}
	private static String muldivd(String fc,String d) {
		if(fc.indexOf(d) < 0)
			return fc;
		String n = "";
		String f1 = "";
		String f2 = "";
		String f3 = "";
		String s = fc.substring(0, fc.indexOf(d));
		for(int i=s.length()-1;i>=0;i--) {
			char c = fc.charAt(i);
			if(Character.isDigit(c) || c == '.') {
				n = n+c;
			}else 
				break;
		}
		f1 = fc.substring(0, fc.indexOf(d)-n.length());
		f2 = '-' + new StringBuffer(n).reverse().toString()+(d=="/-"?'/':'*');
		f3 = fc.substring(fc.indexOf(d)+2);
		fc = f1+f2+f3;
//		System.out.println(fc);
		if(fc.indexOf(d) > -1)
			return muldivd(fc,d);
		return fc;
	}
	private static double[] convertFromfc(String fc) {
		String[] fs = fc.split(",");
		double[] res = new double[fs.length];
		for(int i=0;i<fs.length;i++) {
			res[i] = Double.parseDouble(parseExp(muldiv(fs[i])));
		}
		return res;
	}
	
//	public static void main(String[] ags) {
//		try {
////			System.out.println(getCalculate("0.00001/5C(1)",null));
//			Map<String,Double> cValues = new HashMap<>();
//			cValues.put("C(127.0.0.1:100071_016)", 5.0);
//			System.out.println(getCalculate("5C(127.0.0.1:100071_016)",cValues));
//		}catch(Exception e) {
//			e.printStackTrace();
//			System.out.println("运算公式错误！");
//		}
//		System.out.println(getCalculate("C(127.0.0.1:100071_016)",null));
//		String s = "SUM(c(127.0.0.1:100071_016),12345C(127.0.0.1:100071_001),C(127.0.0.1:100071_002),c(127.0.0.1:100071_003),C(127.0.0.1:100071_004))/5";
////        Pattern p=Pattern.compile("C|c\\([\\s\\S]*\\_[\\d]*\\)");
//        
//        Pattern p = Pattern.compile("([c|C]\\(.*?\\))");
//        
//        Matcher m = p.matcher(s);
//        while (m.find()) {
//            String str = m.group(1);
//            System.out.println(str);
//        }
//	}
	
//	private int rrr() {
//		return 1;
//	}
}
